﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GenericGA.extrandom;

namespace GenericGA.generationmaker.mutation
{
    /// <summary>
    /// Decorator for mutations to make the mutation occur at a probability (mutation rate) rather than always.
    /// </summary>
    public class ProbabilisticMutation : Mutation
    {

        /// <summary>
        /// A random number generator.
        /// </summary>
        private readonly ExtRandom randGen;

        /// <summary>
        /// The probability between 0 and 1 that a mutation will occur every time the Mutate method is called.
        /// </summary>
        public double Rate
        {
            get
            {
                return rate;
            }
            set
            {
                if (rate < 0 || rate > 1)
                {
                    throw new ArgumentException();
                }
                rate = value;
            }
        }
        private double rate;

        /// <summary>
        /// The mutation that will occur.
        /// </summary>
        private readonly Mutation mutation;

        /// <summary>
        /// Constructor to create a ProbabiliticMutation decorator from a mutation rate and a mutation object.
        /// </summary>
        /// <param name="randGen">A random number generator.</param>
        /// <param name="rate">The mutation rate.</param>
        /// <param name="mutation">The mutation to take place.</param>
        public ProbabilisticMutation(ExtRandom randGen, double rate, Mutation mutation)
        {
            this.randGen = randGen;
            Rate = rate;
            this.mutation = mutation;
        }

        /// <summary>
        /// Mutate the chromosome or not depending on the mutation rate.
        /// </summary>
        /// <param name="bits">The chromosome to mutate.</param>
        public override void Mutate(List<ulong> mutant)
        {
            if (randGen.NextBool(rate))
            {
                mutation.Mutate(mutant);
            }
        }

    }
}
